home *** CD-ROM | disk | FTP | other *** search
- /*
- ** termSaveWindow.c
- **
- ** Support routines for saving IFF-ILBM files
- **
- ** Copyright © 1990-1995 by Olaf `Olsen' Barthel
- ** All Rights Reserved
- */
-
- #include "termGlobal.h"
-
- /* Current compression mode. */
-
- #define DUMP 0
- #define RUN 1
-
- /* ByteRun compression data. */
-
- #define MINRUN 3
- #define MAXRUN 128
- #define MAXDAT 128
-
- /* Chunk types. */
-
- #define ID_ILBM MAKE_ID('I','L','B','M')
- #define ID_ANNO MAKE_ID('A','N','N','O')
- #define ID_BMHD MAKE_ID('B','M','H','D')
- #define ID_CMAP MAKE_ID('C','M','A','P')
- #define ID_CAMG MAKE_ID('C','A','M','G')
- #define ID_BODY MAKE_ID('B','O','D','Y')
-
- /* Masking technique. */
-
- #define mskNone 0
-
- /* Compression techniques. */
-
- #define cmpNone 0
- #define cmpByteRun1 1
-
- /* A bitmap header. */
-
- typedef struct
- {
- UWORD w,h; /* raster width & height in pixels */
- WORD x,y; /* position for this image */
- UBYTE nPlanes; /* # source bitplanes */
- UBYTE masking; /* masking technique */
- UBYTE compression; /* compression algorithm */
- UBYTE pad1; /* UNUSED. For consistency, put 0 here.*/
- UWORD transparentColor; /* transparent "color number" */
- UBYTE xAspect,yAspect; /* aspect ratio, a rational number x/y */
- WORD pageWidth,pageHeight; /* source "page" size in pixels */
- } BitMapHeader;
-
- /* A single 8-bit colour register. */
-
- typedef struct
- {
- UBYTE red, /* red component, 0..255 */
- green, /* green component, 0..255 */
- blue; /* blue component, 0..255 */
- } ColorRegister;
-
- /* Local packer data. */
-
- STATIC LONG PackedBytes;
- STATIC BYTE Buffer[MAXDAT + 1];
-
- /* PutDump(register PLANEPTR Destination,register LONG Count):
- *
- * Output a byte dump.
- */
-
- STATIC PLANEPTR __regargs
- PutDump(register PLANEPTR Destination,register LONG Count)
- {
- register PLANEPTR Source = Buffer;
-
- *Destination++ = Count - 1;
- PackedBytes += Count + 1;
-
- while(Count--)
- *Destination++ = *Source++;
-
- return(Destination);
- }
-
- /* PutRun(register PLANEPTR Destination,LONG Count,WORD Char):
- *
- * Output a byte run.
- */
-
- STATIC PLANEPTR __regargs
- PutRun(register PLANEPTR Destination,LONG Count,WORD Char)
- {
- *Destination++ = -(Count - 1);
- *Destination++ = Char;
- PackedBytes += 2;
-
- return(Destination);
- }
-
- /* PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize):
- *
- * Pack a row of bitmap data using ByteRun compression,
- * based on the original "EA IFF 85" pack.c example code.
- */
-
- STATIC LONG __regargs
- PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize)
- {
- register PLANEPTR Source = *SourcePtr;
-
- WORD Buffered = 1,
- RunStart = 0;
- BYTE Mode = DUMP,
- LastChar,
- Char;
-
- PackedBytes = 0;
-
- Buffer[0] = LastChar = Char = *Source++;
-
- RowSize--;
-
- while(RowSize--)
- {
- Buffer[Buffered++] = Char = *Source++;
-
- if(Mode)
- {
- if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
- {
- Destination = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
- Buffer[0] = Char;
- Buffered = 1;
- RunStart = 0;
- Mode = DUMP;
- }
- }
- else
- {
- if(Buffered > MAXDAT)
- {
- Destination = PutDump(Destination,Buffered - 1);
- Buffer[0] = Char;
- Buffered = 1;
- RunStart = 0;
- }
- else
- {
- if(Char == LastChar)
- {
- if(Buffered - RunStart >= MINRUN)
- {
- if(RunStart)
- Destination = PutDump(Destination,RunStart);
-
- Mode = RUN;
- }
- else
- {
- if(!RunStart)
- Mode = RUN;
- }
- }
- else
- RunStart = Buffered - 1;
- }
- }
-
- LastChar = Char;
- }
-
- if(Mode)
- PutRun(Destination,Buffered - RunStart,LastChar);
- else
- PutDump(Destination,Buffered);
-
- *SourcePtr = Source;
-
- return(PackedBytes);
- }
-
- /* PutANNO(struct IFFHandle *Handle):
- *
- * Output `ANNO' chunk.
- */
-
- STATIC BYTE __regargs
- PutANNO(struct IFFHandle *Handle)
- {
- extern UBYTE __far VersTag[];
- WORD Len;
-
- LONG Error;
-
- Len = strlen(&VersTag[1]);
-
- /* Push the `ANNO' chunk on the stack. */
-
- if(!(Error = PushChunk(Handle,0,ID_ANNO,Len)))
- {
- /* Write the creator string. */
-
- if(WriteChunkBytes(Handle,&VersTag[1],Len) == Len)
- {
- /* Pop the `ANNO' chunk. */
-
- if(!(Error = PopChunk(Handle)))
- return(TRUE);
- }
- else
- Error = IoErr();
- }
-
- SetIoErr(Error);
-
- return(FALSE);
- }
-
- /* PutBMHD():
- *
- * Output `BMHD' chunk.
- */
-
- STATIC BYTE __regargs
- PutBMHD(struct IFFHandle *Handle,struct Window *Window,UBYTE Compression,LONG Left,LONG Top,LONG Width,LONG Height)
- {
- struct DisplayInfo DisplayInfo;
- LONG Error = 0;
-
- /* Get the display aspect ratio. */
-
- if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,GetVPModeID(&Window -> WScreen -> ViewPort)))
- {
- BitMapHeader Header;
-
- /* Fill in the bitmap header. */
-
- Header . w = Width;
- Header . h = Height;
- Header . pageWidth = Window -> WScreen -> Width;
- Header . pageHeight = Window -> WScreen -> Height;
- Header . x = Left;
- Header . y = Top;
- Header . nPlanes = GetBitMapDepth(Window -> WScreen -> RastPort . BitMap);
- Header . masking = mskNone;
- Header . compression = Compression;
- Header . pad1 = 0;
- Header . transparentColor = 0;
- Header . xAspect = DisplayInfo . Resolution . x;
- Header . yAspect = DisplayInfo . Resolution . y;
-
- /* Push the `BMHD' chunk on the stack. */
-
- if(!(Error = PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader))))
- {
- /* Write the bitmap header. */
-
- if(WriteChunkBytes(Handle,&Header,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
- {
- /* Pop the `BMHD' chunk. */
-
- if(!(Error = PopChunk(Handle)))
- return(TRUE);
- }
- else
- Error = IoErr();
- }
- }
- else
- Error = ERR_NO_MEM;
-
- if(Error)
- SetIoErr(Error);
-
- return(FALSE);
- }
-
- /* PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort):
- *
- * Output `CMAP' chunk, only 4-bit colour registers
- * are supported so far.
- */
-
- STATIC BYTE __regargs
- PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort)
- {
- LONG Error;
-
- /* Push the `CMAP' chunk on the stack. */
-
- if(!(Error = PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count)))
- {
- ColorRegister Colour;
- LONG i;
- ULONG Value,
- R,G,B;
-
- /* Read and convert all the
- * ColorMap entries (4 bit colour
- * components only).
- */
-
- if(Kick30)
- {
- ULONG RGB[3];
-
- for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
- {
- /* Read colour value. */
-
- GetRGB32(VPort -> ColorMap,i,1,RGB);
-
- /* Store the colour components. */
-
- Colour . red = RGB[0] >> 24;
- Colour . green = RGB[1] >> 24;
- Colour . blue = RGB[2] >> 24;
-
- /* Write the colours. */
-
- if(WriteChunkBytes(Handle,&Colour,3) != 3)
- return(FALSE);
- }
- }
- else
- {
- for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
- {
- /* Read colour value. */
-
- Value = GetRGB4(VPort -> ColorMap,i);
-
- /* Split the value into components. */
-
- R = (Value >> 8) & 0xF;
- G = (Value >> 4) & 0xF;
- B = (Value ) & 0xF;
-
- /* Store the colour components. */
-
- Colour . red = (R << 4) | R;
- Colour . green = (G << 4) | G;
- Colour . blue = (B << 4) | B;
-
- /* Write the colours. */
-
- if(WriteChunkBytes(Handle,&Colour,3) != 3)
- return(FALSE);
- }
- }
-
- /* Pop the `CMAP' chunk. */
-
- if(!(Error = PopChunk(Handle)))
- return(TRUE);
- }
-
- SetIoErr(Error);
-
- return(FALSE);
- }
-
- /* PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort):
- *
- * Output `CAMG' chunk.
- */
-
- STATIC BYTE __regargs
- PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort)
- {
- LONG Error;
-
- if(!(Error = PushChunk(Handle,0,ID_CAMG,sizeof(ULONG))))
- {
- ULONG ViewModes = GetVPModeID(VPort);
-
- if(WriteChunkBytes(Handle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
- {
- if(!(Error = PopChunk(Handle)))
- return(TRUE);
- }
- else
- Error = IoErr();
- }
-
- if(Error)
- SetIoErr(Error);
-
- return(FALSE);
- }
-
- /* PutBODY(struct IFFHandle *Handle)
- *
- * Output `BODY' chunk.
- */
-
- STATIC BYTE __regargs
- PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap,UBYTE Compression)
- {
- BYTE Success = FALSE;
- PLANEPTR *Planes;
- LONG Error = 0;
-
- /* Allocate temporary bitplane pointers. */
-
- if(Planes = (PLANEPTR *)AllocVecPooled(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
- {
- register LONG i;
-
- /* Copy the bitplane pointers. */
-
- for(i = 0 ; i < BitMap -> Depth ; i++)
- Planes[i] = BitMap -> Planes[i];
-
- /* Are we to compress the data? */
-
- if(Compression == cmpByteRun1)
- {
- PLANEPTR PackBuffer;
-
- /* Allocate line compression buffer. */
-
- if(PackBuffer = (PLANEPTR)AllocVecPooled(BitMap -> BytesPerRow * 2,MEMF_ANY))
- {
- /* Push the `BODY' chunk on the stack. */
-
- if(!(Error = PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN)))
- {
- register LONG PackedBytes,
- j;
-
- /* So far, we are quite successful,
- * any write access to fail will
- * cause `Success' to drop to FALSE.
- */
-
- Success = TRUE;
-
- /* Compress all the rows. */
-
- for(i = 0 ; Success && i < BitMap -> Rows ; i++)
- {
- /* Compress all the planes. */
-
- for(j = 0 ; Success && j < BitMap -> Depth ; j++)
- {
- /* Do the compression. */
-
- PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
-
- /* Write the compressed data. */
-
- if(WriteChunkBytes(Handle,PackBuffer,PackedBytes) != PackedBytes)
- {
- Error = IoErr();
-
- Success = FALSE;
- }
- }
- }
-
- /* Pop the `BODY' chunk. */
-
- if(Success)
- {
- if(Error = PopChunk(Handle))
- Success = FALSE;
- }
- }
-
- /* Free the line compression buffer. */
-
- FreeVecPooled(PackBuffer);
- }
- else
- Error = ERR_NO_MEM;
- }
- else
- {
- /* Push the `BODY' chunk on the stack. */
-
- if(!(Error = PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN)))
- {
- register LONG j;
-
- /* So far, we are quite successful,
- * any write access to fail will
- * cause `Success' to drop to FALSE.
- */
-
- Success = TRUE;
-
- /* Compress all the rows. */
-
- for(i = 0 ; Success && i < BitMap -> Rows ; i++)
- {
- /* Compress all the planes. */
-
- for(j = 0 ; Success && j < BitMap -> Depth ; j++)
- {
- /* Write the row. */
-
- if(WriteChunkBytes(Handle,Planes[j],BitMap -> BytesPerRow) != BitMap -> BytesPerRow)
- {
- Error = IoErr();
-
- Success = FALSE;
- }
- else
- Planes[j] += BitMap -> BytesPerRow;
- }
- }
-
- /* Pop the `BODY' chunk. */
-
- if(Success)
- {
- if(Error = PopChunk(Handle))
- Success = FALSE;
- }
- }
- }
-
- /* Free the temporary bitplane pointers. */
-
- FreeVecPooled(Planes);
- }
- else
- Error = ERR_NO_MEM;
-
- if(Error)
- SetIoErr(Error);
-
- /* Return the result. */
-
- return(Success);
- }
-
- /* SaveWindow(STRPTR Name,struct Window *Window):
- *
- * Save the contents of a window to a file.
- */
-
- BYTE __regargs
- SaveWindow(STRPTR Name,struct Window *Window)
- {
- BYTE Success = FALSE,
- NewFile = FALSE,
- Locked = TRUE;
- LONG Error = 0;
-
- LockLayerRom(Window -> RPort -> Layer);
-
- // Datatypes available?
-
- if(DataTypesBase)
- {
- struct BitMap *BitMap;
- struct Screen *Screen = Window -> WScreen;
- LONG Left,Top,
- Width,Height;
- Object *Picture = NULL;
-
- // Keep these handy
-
- Left = Window -> LeftEdge + Window -> BorderLeft;
- Top = Window -> TopEdge + Window -> BorderTop;
- Width = Window -> Width - (Window -> BorderLeft + Window -> BorderRight);
- Height = Window -> Height - (Window -> BorderTop + Window -> BorderBottom);
-
- if(!StatusWindow)
- Height -= StatusDisplayHeight;
-
- // This is where the window contents will go
-
- if(BitMap = AllocBitMap(Width,Height,GetBitMapAttr(Window -> RPort -> BitMap,BMA_DEPTH),NULL,Window -> RPort -> BitMap))
- {
- struct RastPort __aligned RPort;
- LONG NumColours;
-
- // Provide temporary storage
-
- InitRastPort(&RPort);
-
- RPort . BitMap = BitMap;
-
- // Copy the window contents
-
- ClipBlit(Window -> RPort,Window -> BorderLeft,Window -> BorderTop,&RPort,0,0,Width,Height,MINTERM_COPY);
-
- // Release the layer
-
- UnlockLayerRom(Window -> RPort -> Layer);
-
- Locked = FALSE;
-
- // Wait until all data is transferred
-
- WaitBlit();
-
- // Get the number of colours available on this screen
-
- NumColours = Screen -> ViewPort . ColorMap -> Count;
-
- // Create a picture object
-
- if(Picture = NewDTObject("term image",
- DTA_SourceType, DTST_RAM,
- DTA_GroupID, GID_PICTURE,
- PDTA_NumColors, NumColours,
- PDTA_BitMap, BitMap,
- PDTA_ModeID, GetVPModeID(&Screen -> ViewPort),
- TAG_DONE))
- {
- struct ColorRegister *ColourMap;
- struct BitMapHeader *BitMapHeader;
- ULONG *Colours;
-
- // Get the internal data arrays
-
- if(GetDTAttrs(Picture,
- PDTA_BitMapHeader, &BitMapHeader,
- PDTA_ColorRegisters, &ColourMap,
- PDTA_CRegs, &Colours,
- TAG_DONE) == 3)
- {
- LONG i;
-
- // Fill in the bitmap header
-
- BitMapHeader -> bmh_Left = Left;
- BitMapHeader -> bmh_Top = Top;
- BitMapHeader -> bmh_Width = Width;
- BitMapHeader -> bmh_Height = Height;
- BitMapHeader -> bmh_Depth = GetBitMapAttr(BitMap,BMA_DEPTH);
- BitMapHeader -> bmh_PageWidth = Screen -> Width;
- BitMapHeader -> bmh_PageHeight = Screen -> Height;
-
- // Get the 32 colours
-
- GetRGB32(Screen -> ViewPort . ColorMap,0,NumColours,Colours);
-
- // Get the 24 bit colours
-
- for(i = 0 ; i < NumColours ; i++)
- {
- ColourMap[i] . red = (UBYTE)(Colours[i * 3 + 0] >> 24);
- ColourMap[i] . green = (UBYTE)(Colours[i * 3 + 1] >> 24);
- ColourMap[i] . blue = (UBYTE)(Colours[i * 3 + 2] >> 24);
- }
- }
- else
- {
- Error = IoErr();
-
- DisposeDTObject(Picture);
-
- Picture = NULL;
- }
- }
- else
- Error = IoErr();
- }
- else
- Error = ERROR_NO_FREE_STORE;
-
- // Successful so far?
-
- if(Picture)
- {
- BPTR FileHandle;
-
- // Open the output file
-
- if(FileHandle = Open(Name,MODE_NEWFILE))
- {
- // Save the image
-
- if(DoMethod(Picture,DTM_WRITE,NULL,FileHandle,DTWM_IFF,NULL))
- Success = TRUE;
- else
- {
- Error = IoErr();
-
- NewFile = TRUE;
- }
-
- Close(FileHandle);
- }
- else
- Error = IoErr();
-
- DisposeDTObject(Picture);
- }
- else
- {
- if(BitMap)
- FreeBitMap(BitMap);
- }
- }
- else
- {
- struct RastPort *RPort;
- LONG Depth;
-
- /* Get the depth. */
-
- Depth = GetBitMapDepth(Window -> WScreen -> RastPort . BitMap);
-
- if(Depth > 8)
- {
- SetIoErr(ERROR_OBJECT_WRONG_TYPE);
-
- return(FALSE);
- }
-
- /* Allocate a dummy rastport, we will need only
- * to copy the contents of the window into the
- * bitmap.
- */
-
- if(RPort = (struct RastPort *)AllocVecPooled(sizeof(struct RastPort),MEMF_ANY))
- {
- struct BitMap *BitMap;
-
- /* Initialize the rastport with defaults. */
-
- InitRastPort(RPort);
-
- /* Allocate a bitmap. */
-
- if(BitMap = (struct BitMap *)AllocVecPooled(sizeof(struct BitMap),MEMF_ANY))
- {
- LONG Width = Window -> Width - (Window -> BorderLeft + Window -> BorderRight),
- Height = Window -> Height - (Window -> BorderTop + Window -> BorderBottom),
- Left = Window -> LeftEdge + Window -> BorderLeft,
- Top = Window -> TopEdge + Window -> BorderTop;
- WORD i;
-
- if(!StatusWindow)
- Height -= StatusDisplayHeight;
-
- /* Put it into the rastport. */
-
- RPort -> BitMap = BitMap;
-
- /* Initialize it with the window dimensions. */
-
- InitBitMap(BitMap,Depth,Width,Height);
-
- /* Flag success so any allocation
- * to fail in the bitplane allocation
- * loop will indicate failure.
- */
-
- Success = TRUE;
-
- /* Allocate all the bitplanes necessary. */
-
- for(i = 0 ; Success && i < BitMap -> Depth ; i++)
- {
- if(!(BitMap -> Planes[i] = AllocRaster(Width,Height)))
- Success = FALSE;
- }
-
- /* Did we get all the planes we wanted? */
-
- if(Success)
- {
- struct IFFHandle *Handle;
-
- /* Copy the window contents to the
- * local bitmap.
- */
-
- ClipBlit(Window -> RPort,Window -> BorderLeft,Window -> BorderTop,RPort,0,0,Width,Height,MINTERM_COPY);
-
- /* Release the lock on the window layer. */
-
- UnlockLayerRom(Window -> RPort -> Layer);
-
- /* Wait for the data to arrive. */
-
- WaitBlit();
-
- Locked = FALSE;
-
- /* Reset the success indicator. */
-
- Success = FALSE;
-
- /* Allocate an iff handle. */
-
- if(Handle = AllocIFF())
- {
- /* Open a file for write access. */
-
- if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
- {
- /* Remember that we succeeded
- * in creating a new file.
- */
-
- NewFile = TRUE;
-
- /* Tell iffparse.library that it's
- * a plain AmigaDOS file handle.
- */
-
- InitIFFasDOS(Handle);
-
- /* Open the file for writing. */
-
- if(!(Error = OpenIFF(Handle,IFFF_WRITE)))
- {
- /* Push parent chunk on the
- * stack.
- */
-
- if(!(Error = PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN)))
- {
- /* Output all the chunk data. */
-
- if(PutANNO(Handle))
- {
- UBYTE Compression;
-
- /* Don't compress the bitmap if
- * isn't really worth it.
- */
-
- if(BitMap -> BytesPerRow > 4)
- Compression = cmpByteRun1;
- else
- Compression = cmpNone;
-
- if(PutBMHD(Handle,Window,Compression,Left,Top,Width,Height))
- {
- if(PutCMAP(Handle,&Window -> WScreen -> ViewPort))
- {
- if(PutCAMG(Handle,&Window -> WScreen -> ViewPort))
- {
- if(PutBODY(Handle,BitMap,Compression))
- {
- /* Pop the parent chunk
- * from the stack.
- */
-
- if(!(Error = PopChunk(Handle)))
- Success = TRUE;
- }
- else
- Error = IoErr();
- }
- else
- Error = IoErr();
- }
- else
- Error = IoErr();
- }
- else
- Error = IoErr();
- }
- else
- Error = IoErr();
- }
-
- /* Close the iff handle. */
-
- CloseIFF(Handle);
- }
-
- /* Close the file. */
-
- if(!Close(Handle -> iff_Stream))
- {
- Error = IoErr();
-
- Success = FALSE;
- }
- }
- else
- Error = IoErr();
-
- /* Free the iff handle. */
-
- FreeIFF(Handle);
- }
- else
- Error = ERR_NO_MEM;
- }
- else
- Error = ERR_NO_MEM;
-
- /* Free all bitplanes. */
-
- for(i = 0 ; i < BitMap -> Depth ; i++)
- {
- if(BitMap -> Planes[i])
- FreeRaster(BitMap -> Planes[i],Width,Height);
- }
-
- /* Free the bitmap. */
-
- FreeVecPooled(BitMap);
- }
- else
- Error = ERR_NO_MEM;
-
- /* Free the rastport. */
-
- FreeVecPooled(RPort);
- }
- else
- Error = ERR_NO_MEM;
- }
-
- /* Release the window layer in case it is still locked. */
-
- if(Locked)
- UnlockLayerRom(Window -> RPort -> Layer);
-
- /* If successful, clear the `executable' bit. */
-
- if(Success)
- {
- AddProtection(Name,FIBF_EXECUTE);
-
- if(Config -> MiscConfig -> CreateIcons)
- AddIcon(CaptureName,FILETYPE_PICTURE,TRUE);
- }
- else
- {
- /* Delete the remains of the file. */
-
- if(NewFile)
- DeleteFile(Name);
- }
-
- /* Return the result. */
-
- return(Success);
- }
-